#pragma once

#include "Parameter.h"

#include "Operation.h"
#include "ParameterSet.h"
#include "ValueSpecification.h"

namespace uml {

const QString Parameter::default2_default_ = "";
const bool Parameter::isException_default_ = false;
const bool Parameter::isStream_default_ = false;
Parameter::Parameter(const QString& umlType)
    : NamedElement(umlType) {}

void Parameter::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    MultiplicityElement::fromJson(json, errorList);
    ConnectableElement::fromJson(json, errorList);
    NamedElement::fromJson(json, errorList);
    default2_ = json.value("default2").toString(default2_default_);
    defaultValue_ = JsonSerializable::create<ValueSpecification>(
        json.value("defaultValue"), errorList
    );

    direction_ =
        (ParameterDirectionKind)json.value("direction").toInt((int)direction_);
    effect_ = (ParameterEffectKind)json.value("effect").toInt((int)effect_);
    isException_ = json.value("isException").toBool(isException_default_);
    isStream_ = json.value("isStream").toBool(isStream_default_);
    operation_ =
        JsonSerializable::create<Operation>(json.value("operation"), errorList);

    JsonSerializable::fromJsonArray(
        parameterSets_, "parameterSets", json, errorList
    );
}

void Parameter::toJson(QJsonObject& json) {
    MultiplicityElement::toJson(json);
    ConnectableElement::toJson(json);
    NamedElement::toJson(json);
    if (default2_ != default2_default_) {
        json.insert("default2", default2_);
    }
    if (defaultValue_) {
        QJsonObject defaultValue_json;
        defaultValue_->toJson(defaultValue_json);
        json.insert("defaultValue", defaultValue_json);
    }
    json.insert("direction", (int)direction_);
    json.insert("effect", (int)effect_);
    if (isException_ != isException_default_) {
        json.insert("isException", isException_);
    }
    if (isStream_ != isStream_default_) {
        json.insert("isStream", isStream_);
    }
    if (operation_) {
        QJsonObject operation_json;
        operation_->toJson(operation_json);
        json.insert("operation", operation_json);
    }
    JsonSerializable::toJsonArray(parameterSets_, "parameterSets", json);
}

/// <summary>
/// default2 getter
/// A String that represents a value to be used when no argument is supplied for the
/// Parameter.
/// </summary>
QString Parameter::default2() const {
    return default2_;
}

/// <summary>
/// default2 setter
/// A String that represents a value to be used when no argument is supplied for the
/// Parameter.
/// </summary>
void Parameter::setDefault2(const QString& value) {
    default2_ = value;
}

/// <summary>
/// defaultValue getter
/// Specifies a ValueSpecification that represents a value to be used when no
/// argument is supplied for the Parameter.
/// </summary>
shared_ptr<ValueSpecification> Parameter::defaultValue() const {
    return defaultValue_;
}

/// <summary>
/// defaultValue setter
/// Specifies a ValueSpecification that represents a value to be used when no
/// argument is supplied for the Parameter.
/// </summary>
void Parameter::setDefaultValue(shared_ptr<ValueSpecification> value) {
    defaultValue_ = value;
}

/// <summary>
/// direction getter
/// Indicates whether a parameter is being sent into or out of a behavioral element.
/// </summary>
ParameterDirectionKind Parameter::direction() const {
    return direction_;
}

/// <summary>
/// direction setter
/// Indicates whether a parameter is being sent into or out of a behavioral element.
/// </summary>
void Parameter::setDirection(ParameterDirectionKind value) {
    direction_ = value;
}

/// <summary>
/// effect getter
/// Specifies the effect that executions of the owner of the Parameter have on
/// objects passed in or out of the parameter.
/// </summary>
ParameterEffectKind Parameter::effect() const {
    return effect_;
}

/// <summary>
/// effect setter
/// Specifies the effect that executions of the owner of the Parameter have on
/// objects passed in or out of the parameter.
/// </summary>
void Parameter::setEffect(ParameterEffectKind value) {
    effect_ = value;
}

/// <summary>
/// isException getter
/// Tells whether an output parameter may emit a value to the exclusion of the other
/// outputs.
/// </summary>
bool Parameter::isException() const {
    return isException_;
}

/// <summary>
/// isException setter
/// Tells whether an output parameter may emit a value to the exclusion of the other
/// outputs.
/// </summary>
void Parameter::setIsException(bool value) {
    isException_ = value;
}

/// <summary>
/// isStream getter
/// Tells whether an input parameter may accept values while its behavior is
/// executing, or whether an output parameter may post values while the behavior is
/// executing.
/// </summary>
bool Parameter::isStream() const {
    return isStream_;
}

/// <summary>
/// isStream setter
/// Tells whether an input parameter may accept values while its behavior is
/// executing, or whether an output parameter may post values while the behavior is
/// executing.
/// </summary>
void Parameter::setIsStream(bool value) {
    isStream_ = value;
}

/// <summary>
/// operation getter
/// The Operation owning this parameter.
/// </summary>
shared_ptr<Operation> Parameter::operation() const {
    return operation_;
}

/// <summary>
/// operation setter
/// The Operation owning this parameter.
/// </summary>
void Parameter::setOperation(shared_ptr<Operation> value) {
    operation_ = value;
}

/// <summary>
/// parameterSets getter
/// The ParameterSets containing the parameter. See ParameterSet.
/// </summary>
vector<shared_ptr<ParameterSet>>& Parameter::parameterSets() {
    return parameterSets_;
}

} // namespace uml
